package my.graduation.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.jsonwebtoken.Claims;
import my.graduation.constant.JwtClaimsConstant;
import my.graduation.dto.*;
import my.graduation.entity.*;
import my.graduation.enums.HttpCodeEnums;
import my.graduation.mapper.ExaminationRecordMapper;
import my.graduation.mapper.PatientMapper;
import my.graduation.mapper.RegistrationRecordMapper;
import my.graduation.properties.JwtProperties;
import my.graduation.result.Result;
import my.graduation.service.PatientService;
import my.graduation.util.JwtUtil;
import my.graduation.util.MedicalCardGenerator;
import my.graduation.vo.DoctorVO;
import my.graduation.vo.PatientLoginVO;
import my.graduation.vo.PatientVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: RavenLyn
 * @Date: 2024-11-28
 */
@Service
public class PatientServiceImpl extends ServiceImpl<PatientMapper, Patient> implements PatientService  {

    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 患者登录
     * @param dto
     * @return
     */
    @Override
    public Result<PatientLoginVO> login(PatientLoginDto dto) {
        // 1 正常登录
        // 手机号/诊疗卡号 和 密码都非空
        if(StringUtils.isNotBlank(dto.getPassword())){
            Patient patient = new Patient();
            if(StringUtils.isNotBlank(dto.getPhone()) &&
                    StringUtils.isBlank(dto.getMedicalCard())){
                patient = getOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getPhone, dto.getPhone()));
            }
            if(StringUtils.isNotBlank(dto.getMedicalCard()) &&
                    StringUtils.isBlank(dto.getPhone())){
                patient = getOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getMedicalCard, dto.getMedicalCard()));
            }
            if(patient == null){
                return Result.error(HttpCodeEnums.DATA_NOT_EXIST);
            }
            // 2 对比密码 MD5加密
            String pswd = DigestUtils.md5DigestAsHex(dto.getPassword().getBytes());
            if(!pswd.equals(patient.getPassword())){
                return Result.error(HttpCodeEnums.LOGIN_PASSWORD_ERROR);
            }
            // 3 返回数据 patient+authorization
            Map<String,Object> claims = new HashMap<>();
            claims.put(JwtClaimsConstant.PATIENT_ID,patient.getId());
            String authorization = JwtUtil.createJWT(
                    jwtProperties.getPatientSecretKey(),
                    jwtProperties.getPatientTtl(),
                    claims
            );
            PatientLoginVO patientLoginVO = new PatientLoginVO();
            BeanUtils.copyProperties(patient,patientLoginVO);
            patientLoginVO.setAuthorization(authorization);
            return Result.success(patientLoginVO);
        }else {
            return Result.error(HttpCodeEnums.LOGIN_IS_BLANK);
        }
    }

    /**
     * 患者登出
     * @param dto
     * @return
     */
    @Override
    public Result logout(PatientLogoutDto dto) {
        if(StringUtils.isNotBlank(dto.getAuthorization())){
            String authorization = dto.getAuthorization();
            Claims claims = JwtUtil.parseJWT(jwtProperties.getPatientSecretKey(),authorization);
            Date exp = claims.getExpiration();
            long expMillis = exp.getTime() / 1000;
            long currentTimeSeconds = System.currentTimeMillis() / 1000;
            if (expMillis < currentTimeSeconds) { // token已过期
                return Result.error(HttpCodeEnums.INVALID_TOKEN_OR_EXPIRED);
            }
            redisTemplate.opsForValue().set(authorization, null, (expMillis - currentTimeSeconds), TimeUnit.SECONDS);
            return Result.success();
        }else {
            return Result.error(HttpCodeEnums.INVALID_TOKEN_OR_EXPIRED);
        }
    }

    /**
     * 患者注册
     * @param dto
     * @return
     */
    @Override
    public Result register(PatientRegisterDto dto) {
        // 1.添加患者数据
        if(dto == null){
            return Result.error(HttpCodeEnums.REGISTER_IS_BLANK);
        }
        Patient patient = new Patient();
        BeanUtils.copyProperties(dto,patient);
        // 2.密码加密
        String pswd = DigestUtils.md5DigestAsHex(dto.getPassword().getBytes());
        patient.setPassword(pswd);

        // 3.注册成功系统生成医疗卡号
        patient.setMedicalCard(MedicalCardGenerator.generateCardId());
        boolean i = save(patient);
        if(i){
            return Result.success();
        }else {
            return Result.error(HttpCodeEnums.SYSTEM_ERROR);
        }
    }



    /**
     * 患者忘记密码
     * @param dto
     * @return
     */
    @Override
    public Result forget(PatientForgetDto dto) {
        // 1 表单非空
        if(StringUtils.isNotBlank(dto.getPassword()) && StringUtils.isNotBlank(dto.getPhone())){
            // 2 验证手机号是否对应一个患者
            Patient patient = getOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getPhone, dto.getPhone()));
            if(patient == null){
                return Result.error(HttpCodeEnums.DATA_NOT_EXIST);
            }
            // 3 密码MD5加密
            String pswd = DigestUtils.md5DigestAsHex(dto.getPassword().getBytes());
            patient.setPassword(pswd);
            // 4 修改密码
            updateById(patient);
            return Result.success();
        }else {
            return Result.error(HttpCodeEnums.SYSTEM_ERROR);
        }
    }

    /**
     * 获取患者列表信息
     * @return
     */
    @Override
    public Result<List<PatientVO>> getList() {
        List<Patient> patientList = list();

        return getListMethod(patientList);
    }

    /**
     * 条件获取患者信息
     * @param dto
     * @return
     */
    @Override
    public Result<List<PatientVO>> getListByCon(PatientInfoDto dto) {
        List<Patient> patientList = list(Wrappers.<Patient>lambdaQuery()
                .like(Patient::getName, dto.getName()));

        return getListMethod(patientList);
    }

    /**
     * 获取患者信息封装method
     * @param patientList
     * @return
     */
    public Result<List<PatientVO>> getListMethod(List<Patient> patientList){
        List<PatientVO> patientVOList = new ArrayList<>();
        for(Patient patient : patientList){
            PatientVO patientVO = new PatientVO();
            BeanUtils.copyProperties(patient,patientVO);
            patientVOList.add(patientVO);
        }

        return Result.success(patientVOList);
    }

    /**
     * 新增患者信息
     * @return
     */
    @Override
    public Result add(PatientInfoDto dto) {
        //非空校验
        if(StringUtils.isNotBlank(dto.getName()) &&
                StringUtils.isNotBlank(dto.getPhone()) &&
                dto.getGender() != null &&
                dto.getBirth() != null){

            Patient patient = new Patient();
            BeanUtils.copyProperties(dto,patient);
            // 初始化密码
            patient.setPassword(DigestUtils.md5DigestAsHex(("12345").getBytes()));
            // 初始化医疗卡号
            patient.setMedicalCard(MedicalCardGenerator.generateCardId());
            boolean i = save(patient);
            if (i) {
                return Result.success();
            } else {
                return Result.error(HttpCodeEnums.SYSTEM_ERROR);
            }
        }else {
            return Result.error(HttpCodeEnums.INFO_IS_BLANK);
        }
    }

    /**
     * 修改患者信息
     * @return
     */
    @Override
    public Result update(PatientInfoDto dto) {
        //非空校验
        if(dto.getId() != null){
            Patient patient = new Patient();
            BeanUtils.copyProperties(dto,patient);
            boolean i = updateById(patient);
            if (i) {
                return Result.success();
            } else {
                return Result.error(HttpCodeEnums.SYSTEM_ERROR);
            }
        }else {
            return Result.error(HttpCodeEnums.DATA_NOT_EXIST);
        }
    }

    /**
     * 删除患者信息
     * @return
     */
    @Override
    public Result delete(PatientInfoDto dto) {
        //非空校验
        if(dto.getId() != null){
            Patient patient = new Patient();
            BeanUtils.copyProperties(dto,patient);
            boolean i = removeById(patient);
            if (i) {
                return Result.success();
            } else {
                return Result.error(HttpCodeEnums.SYSTEM_ERROR);
            }
        }else {
            return Result.error(HttpCodeEnums.DATA_NOT_EXIST);
        }
    }

    /**
     * 患者获取个人信息
     * @param dto
     * @return
     */
    @Override
    public Result<PatientVO> getPersonal(PatientInfoDto dto) {
        if(dto.getId() != null){
            Patient one = getOne(Wrappers.<Patient>lambdaQuery().eq(Patient::getId, dto.getId()));
            PatientVO patientVO = new PatientVO();
            BeanUtils.copyProperties(one,patientVO);
            return Result.success(patientVO);
        }else {
            return Result.error(HttpCodeEnums.DATA_NOT_EXIST);
        }
    }

    /**
     * 患者修改密码
     * @param dto
     * @return
     */
    @Override
    public Result repass(RepassDto dto) {
        if(dto.getId() != null &&
                dto.getNewPass() != null &&
                dto.getOldPass() != null){
            Patient one = getOne(Wrappers.<Patient>lambdaQuery()
                    .eq(Patient::getId, dto.getId()));
            String oldPswd = DigestUtils.md5DigestAsHex(dto.getOldPass().getBytes());

            if(oldPswd.equals(one.getPassword())){ //旧密码匹配成功
                String newPswd = DigestUtils.md5DigestAsHex(dto.getNewPass().getBytes());
                update(Wrappers.<Patient>lambdaUpdate()
                        .eq(Patient::getId,dto.getId())
                        .set(Patient::getPassword,newPswd));
                return Result.success();
            }else {
                return Result.error(HttpCodeEnums.OLD_PASSWORD_WRONG);
            }
        }else {
            return Result.error(HttpCodeEnums.DATA_NOT_EXIST);
        }
    }

    @Autowired
    private RegistrationRecordMapper regRecordMapper;
    @Autowired
    private ExaminationRecordMapper examRecordMapper;

    /**
     * 获取该患者待就诊 / 检查的所有项目个数
     * @param dto
     * @return
     */
    @Override
    public Result<Integer> getCount(PatientInfoDto dto) {
        if(dto.getId() != null){
            LocalDate today = LocalDate.now();
            int regCount = regRecordMapper.getCount(dto.getId(),today);
            int examCount = examRecordMapper.getCount(dto.getId(),today);
            int total = regCount + examCount;
            return Result.success(total);
        }else {
            return Result.error(HttpCodeEnums.DATA_NOT_EXIST);
        }
    }
}
